#include "graph_support/fakes/ChessBoard.h"

//namespace test_gs_fakes
//{

ChessBoard::GrVertex::GrVertex( int col, int row )
	: std::pair< int, int >( col, row )
{
}

bool ChessBoard::GrVertex::operator == ( const GrVertex & that ) const
{
	return first == that.first && second == that.second;
}

ChessBoard::GrEdge::GrEdge( ChessBoard & cb, const ChessBoard::GrVertex & edgBeg, const ChessBoard::GrVertex & edgEnd )
	: cb( & cb )
	, edgBeg( edgBeg )
	, edgEnd( edgEnd )
{
}

ChessBoard::GrEdge::GrEdge()
	: cb( NULL )
{
}

const ChessBoard::GrVertex ChessBoard::GrEdge::beg()
{
	return edgBeg;
}

const ChessBoard::GrVertex ChessBoard::GrEdge::end()
{
	return edgEnd;
}

size_t ChessBoard::GrEdge::begId()
{
	return Graph::NOT_A_VERTEX_ID;
}

size_t ChessBoard::GrEdge::endId()
{
	return cb->vert2num( edgEnd );
	return Graph::NOT_A_VERTEX_ID;
}

ChessBoard::EdgeAttributes & ChessBoard::GrEdge::getAttributes()
{
	return attributes;
}

bool ChessBoard::GrEdge::operator == ( const GrEdge & that ) const
{
	return edgBeg == that.edgBeg && edgEnd == that.edgEnd && attributes == that.attributes && cb == that.cb;
}

ChessBoard::VertexIterator::VertexIterator( const ChessBoard & chb, bool isEnd )
	: chb( chb )
	, curVert( 0 )
{
	if ( isEnd )
	{
		curVert = chb.getVertexCount();
	}
}
const ChessBoard::VertexIterator & ChessBoard::VertexIterator::operator ++ ()
{
	curVert++;
	return * this;
}
bool ChessBoard::VertexIterator::operator != ( const VertexIterator & that ) const
{
	return curVert != that.curVert || &chb != &that.chb;
}
const ChessBoard::GrVertex ChessBoard::VertexIterator::operator * ()
{
	return chb.num2vert( curVert );
}
GRAPH_SUPPORT_NS::utils::PtrAccessOpSimulator< ChessBoard::GrVertex > ChessBoard::VertexIterator::operator -> ()
{
	return GRAPH_SUPPORT_NS::utils::PtrAccessOpSimulator< GrVertex >( chb.num2vert( curVert ) );
}

ChessBoard::EdgeIterator::EdgeIterator( ChessBoard & chb, int c, int r, bool isEnd )
	: chb( & chb )
	, c( c )
	, r( r )
	, shStepPos( 0 )
{
	if ( isEnd )
	{
		shStepPos = ChessBoard::DSTEPS_COUNT;
	} else
	{
		shpos2good();
	}
}

const ChessBoard::EdgeIterator & ChessBoard::EdgeIterator::operator ++ ()
{
	shStepPos++;
	shpos2good();
	return * this;
}

bool ChessBoard::EdgeIterator::operator != ( const EdgeIterator & that ) const
{
	return ! ( ( * this ) == that );
}

bool ChessBoard::EdgeIterator::operator == ( const EdgeIterator & that ) const
{
	return shStepPos == that.shStepPos && chb == that.chb && r == that.r && c == that.c;
}

ChessBoard::GrEdgePtr ChessBoard::EdgeIterator::operator * ()
{
	return GrEdgePtr( GrEdge( * chb,
			GrVertex( c, r ),
			GrVertex( c + ChessBoard::DELTA_STEPS_C[shStepPos], r + ChessBoard::DELTA_STEPS_R[shStepPos] ) ) );
}

ChessBoard::GrEdgePtr ChessBoard::EdgeIterator::operator -> ()
{
	return * ( * this );
}

void ChessBoard::EdgeIterator::shpos2good()
{
	while ( shStepPos < ChessBoard::DSTEPS_COUNT &&
			!chb->areCoordinatesGood( c + ChessBoard::DELTA_STEPS_C[shStepPos],
				r + ChessBoard::DELTA_STEPS_R[shStepPos] ) )
	{
		shStepPos++;
	}
}

ChessBoard::ChessBoard( size_t rows, size_t columns )
	: rows( rows )
	, columns( columns )
{
}

size_t ChessBoard::getVertexCount() const
{
	return rows * columns;
}

ChessBoard::VertexIterator ChessBoard::getVerticesBeg()
{
	return VertexIterator( * this );
}

ChessBoard::VertexIterator ChessBoard::getVerticesEnd()
{
	return VertexIterator( * this, true );
}

ChessBoard::EdgeIterator ChessBoard::getEdgsBeg( const GrVertex & v )
{
	return EdgeIterator( * this, v.first, v.second );
}

ChessBoard::EdgeIterator ChessBoard::getEdgsEnd( const GrVertex & v )
{
	return EdgeIterator( * this, v.first, v.second, true );
}

ChessBoard::EdgeIterator ChessBoard::getEdgsBegId( size_t vid )
{
	GrVertex vert = num2vert( vid );
	return EdgeIterator( *this, vert.first, vert.second );
}

ChessBoard::EdgeIterator ChessBoard::getEdgsEndId( size_t vid )
{
	GrVertex vert = num2vert( vid );
	return EdgeIterator( * this, vert.first, vert.second, true );
}

size_t ChessBoard::vert2num( const ChessBoard::GrVertex & v ) const
{
	int c = v.first;
	int r = v.second;
	return c * columns + r;
}

const ChessBoard::GrVertex ChessBoard::num2vert( size_t vid ) const
{
	int c = vid / columns;
	int r = vid % columns;
	return GrVertex( c, r );
}

bool ChessBoard::areCoordinatesGood( int c, int r )
{
	return c >= 0 && c < columns && r >= 0 && r < rows ;
}

const int ChessBoard::DELTA_STEPS_C[] = {  1, -1,  1, -1,  2,  2, -2, -2 };
const int ChessBoard::DELTA_STEPS_R[] = {  2,  2, -2, -2,  1, -1,  1, -1 };

//}

	std::iostream & operator << ( std::iostream & ostr, const /*test_gs_fakes::*/ChessBoard::GrVertex & vert )
	{
		ostr << "chess-pos:<" << vert.first << "," << vert.second << ">";
		return ostr;
	}

int computeKnightOutcomes( int rows, int columns )
{
	int chr[] = {  2,  2, -2, -2,  1, -1,  1, -1 };
	int chc[] = {  1, -1,  1, -1,  2,  2, -2, -2 };
	int chn = sizeof( chr ) / sizeof( int );

	int result = 0;
	for ( int i = 0; i < rows; i++ )
	{
		for ( int j = 0; j < columns; j++ )
		{
			for ( int k = 0; k < chn; k++ )
			{
				int r = i + chr[k];
				int c = j + chc[k];
				if ( r >= 0 && r < columns && c >= 0 && c < rows )
				{
					result++;
				}
			}
		}
	}
	return result;
}
